package game;

import java.util.LinkedList;
import java.util.List;

public class Game
{
	
	public Game(String name, int numPlayers, int numMoves)
	{
		this.setName(name);
		this.setNumPlayers(numPlayers);
		this.setNumMoves(numMoves);
		
		itsPlayers = new LinkedList<Player>();
		for(int i = 0; i < numPlayers; ++i)
		{
			itsPlayers.add(new Player(i + 1));
		}
	}
	
	/*
	 * operation play()
	 * play the game
	 */
	public void play()
	{
		System.out.println("Playing " + getName() + " game with " + getNumPlayers() + " players, for up to " + getNumMoves() + " moves. Initial board state:");
		itsBoard.display();
		
		step = 0;
		while(isFinished() == false)
		{
			// 1. get the next player
			Player player = nextPlayer();
			// 2. obtain the next move
			Move nextMove = itsMoveObtainer.obtainMove(itsBoard, player);
			// 3. execute the next move
			nextMove.execute(itsBoard);
			// 4. display the board
			itsBoard.display();
			++step;
		}
		// display the results and the history of this game
		displayResults();
		displayHistory();
	}
	
	/*
	 * operation isFinished
	 * check if a game is finished
	 */
	private boolean isFinished()
	{
		return itsGameRules.isFinished();
	}
	
	/*
	 * operation nextPlayer()
	 * Strategy pattern to get the next player who gets to play
	 */
	private Player nextPlayer()
	{
		return itsGameRules.nextPlayer(itsPlayers);
	}
	
	private void displayResults()
	{
		System.out.println("Finished game " + name + "\nResults:");
		System.out.println(numPlayers + " players played this game");
		System.out.println(step + " moves were taken before the game ended");
		int status = itsGameRules.getCompletionStatus();
		if(status == 1)
		{
			System.out.println("The winner is player " + itsGameRules.getWinner().getId());
		}
		else if(status == 0)
		{
			System.out.println("There is no winner, the game resulted in a draw");
		}
		else
		{
			System.out.println("There is no winner, the game stopped after " + numMoves + " moves, less than the maximum possible moves - " + itsGameRules.getMaximumPossibleMoves());
		}
	}
	
	private void displayHistory()
	{
		GameHistory history = new GameHistory(name);
		history.load();
		history.addGameResults(generateGameResults());
		history.display();
		history.save();
	}
	
	/*
	 * operation generateReport()
	 * generate a report of the game
	 */
	private GameResults generateGameResults()
	{
		if(itsGameRules.getWinner() != null)
		{
			return new GameResults(getNumPlayers(), getStep(), itsGameRules.getWinner().getId());
		}
		else
		{
			return new GameResults(getNumPlayers(), getStep(), 0);
		}
	}
	
	/*
	 * All getters and setters
	 */
	public void setName(String name)
	{
		this.name = name;
	}

	public String getName()
	{
		return name;
	}
	
	public void setNumPlayers(int numPlayers)
	{
		this.numPlayers = numPlayers;
	}

	public int getNumPlayers()
	{
		return numPlayers;
	}

	public void setNumMoves(int numMoves)
	{
		this.numMoves = numMoves;
	}

	public int getNumMoves()
	{
		return numMoves;
	}

	public void setItsBoard(Board itsBoard)
	{
		this.itsBoard = itsBoard;
	}

	public Board getItsBoard()
	{
		return itsBoard;
	}

	public void setItsPlayers(List<Player> itsPlayers)
	{
		this.itsPlayers = itsPlayers;
	}

	public List<Player> getItsPlayers()
	{
		return itsPlayers;
	}

	public void setStep(int step)
	{
		this.step = step;
	}

	public int getStep()
	{
		return step;
	}

	public void setItsGameRules(GameRules itsGameRules)
	{
		this.itsGameRules = itsGameRules;
	}

	public GameRules getItsGameRules()
	{
		return itsGameRules;
	}

	public void setItsMoveObtainer(MoveObtainer itsMoveObstainer)
	{
		this.itsMoveObtainer = itsMoveObstainer;
	}

	public MoveObtainer getItsMoveObtainer()
	{
		return itsMoveObtainer;
	}

	private String name;
	private int numPlayers, numMoves, step;
	private Board itsBoard;
	private GameRules itsGameRules;
	private MoveObtainer itsMoveObtainer;
	
	//private TurnStrategy itsNextPlayerStrategy;
	//private OneMoveImplementor itsNextMoveImplementor;
	
	
	private List<Player> itsPlayers;
}
